using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;

namespace System.Net
{
    public static class IPAddressExtentions
    {
        public static IEnumerable<PingReply> Pinging(this IPAddress address, int Count,
                                     int BufferLength = 32, bool DontFragment = true, int Timeout = 120)
        {

            var buffer = new byte[BufferLength];
            using(var ping = new Ping())
                for(var i = 0; i < Count; i++)
                {
                    var options = new PingOptions { DontFragment = DontFragment };
                    yield return ping.Send(address, Timeout, buffer, options);
                }
        }

        public static PingReply Ping(this IPAddress address,
                                     int BufferLength = 32, bool DontFragment = true, int Timeout = 120)
        {
            using(var ping = new Ping())
            {
                var options = new PingOptions { DontFragment = DontFragment };
                var buffer = new byte[BufferLength];
                return ping.Send(address, Timeout, buffer, options);
            }
        }



        public static PingReply[] Ping(this IPAddress address, int Count,
                                       int BufferLength = 32, bool DontFragment = true, int Timeout = 120, Action<int, int, PingReply> OnPing = null)
        {
            var result = new PingReply[Count];
            var buffer = new byte[BufferLength];
            using(var ping = new Ping())
                for(var i = 0; i < Count; i++)
                {
                    var options = new PingOptions { DontFragment = DontFragment };
                    result[i] = ping.Send(address, Timeout, buffer, options);
                    if(OnPing != null) OnPing(i, Count, result[i]);
                }
            return result;
        }

        public static IPHostEntry GetHostEntry(this IPAddress address) { return Dns.GetHostEntry(address); }

        public static string GetHostName(this IPAddress address)
        {
            return Dns.GetHostEntry(address).HostName;
        }

        public static IEnumerable<PingReply> TraceRoute(this IPAddress ip, int Timeout = 500, int MaxJumps = 100)
        {
            var buffer = new byte[32];
            var pinger = new Ping();
            var options = new PingOptions { Ttl = 1 };
            //var count = 0;
            var pings = pinger.SelectObj<Ping, PingReply>(r =>
                        r.Next(r.Object.Send(ip, Timeout, buffer, options)))
                        .ForeachLeazy(p => options.Ttl++)
                //.ForeachLeazy(p =>
                //{
                //    if(p.Status == IPStatus.TtlExpired)
                //    {
                //        options.Ttl++;
                //        count = 0;
                //    }
                //    else
                //        count++;
                //})
                        .TakeWhile((p, i) => p.Status != IPStatus.Success && i < MaxJumps /* && count < 10*/)
                        .AppendLast(ip.Ping(Timeout: Timeout));
            foreach(var ping in pings)
                yield return ping;
        }
    }
}